

#include "lcd_internal.h"

#if MODULE_CHECK_ENABLED( LCD_QSPI )
#error "must not define qspi lcd interface!!!"
#endif

GUI_RAM_CODE
bool lcd_write_completed(void)
{
    if( lcd_wrctl.block_write ) 
    {
        if( lcd_wrctl.offset < lcd_wrctl.size )
        {
            uint16_t remain = lcd_wrctl.size - lcd_wrctl.offset;
            if( remain > LCD_XFER_MAX_SIZE )
            {
                remain = LCD_XFER_MAX_SIZE;
            }
            LCD_SEND_DATA_ASYNC( lcd_wrctl.pdata + lcd_wrctl.offset, remain );
            lcd_wrctl.offset += remain;
        }
        else 
        {
            lcd_wrctl.blocks.used ++;
            if( lcd_wrctl.blocks.used < lcd_wrctl.blocks.count )
            {
                // check next row 
                lcd_wrctl.pdata += lcd_wrctl.blocks.offset; // next block  
                lcd_wrctl.offset = 0; 
                uint16_t remain = lcd_wrctl.size;
                if( remain > LCD_XFER_MAX_SIZE )
                {
                    remain = LCD_XFER_MAX_SIZE; 
                }
                
                LCD_SEND_DATA_ASYNC( lcd_wrctl.pdata, remain );
                lcd_wrctl.offset = remain; //start a block 
            }
            else 
            {
                lcd_wrctl.isbusy = false; 
            }
        }
    }
    else 
    {
        if( lcd_wrctl.offset < lcd_wrctl.size )
        {
            uint16_t remain = lcd_wrctl.size - lcd_wrctl.offset;
            if( remain > LCD_XFER_MAX_SIZE )
            {
                remain = LCD_XFER_MAX_SIZE;
            }
            LCD_SEND_DATA_ASYNC( lcd_wrctl.pdata + lcd_wrctl.offset, remain );
            lcd_wrctl.offset += remain;
        }
        else 
        {
            lcd_wrctl.isbusy = false; 
        }
    }
    return lcd_wrctl.isbusy;
}

void lcd_write_data_value(uint8_t data)
{
    lcd_write_data(&data,1);
}

static void driver_init(void)
{
    LCD_SET_nRESET;
    LCD_DELAY_MS( 10 );
    LCD_SET_RESET;
    LCD_DELAY_MS(20);
    LCD_SET_nRESET;
    LCD_DELAY_MS( 20 );

#if 0//old
    lcd_write_command(0xFE);
    lcd_write_command(0xEF);
    lcd_write_command(0xEB);
    lcd_write_data_value(0x14);  
    lcd_write_command(0x84);
    lcd_write_data_value(0x60);	
        
    lcd_write_command(0x85);	
    lcd_write_data_value(0xFF);

    lcd_write_command(0x86);	
    lcd_write_data_value(0xFF);
    lcd_write_command(0x87);	
    lcd_write_data_value(0xFF);//ff en	
    lcd_write_command(0x8E);	
    lcd_write_data_value(0xFF);
    lcd_write_command(0x8F);	
    lcd_write_data_value(0xFF);
        
    lcd_write_command(0x88);
    lcd_write_data_value(0x0A);
    lcd_write_command(0x89);
    lcd_write_data_value(0x21);		

    lcd_write_command(0x8B);	
    lcd_write_data_value(0x80);
    lcd_write_command(0x8C);	
    lcd_write_data_value(0x01);

    lcd_write_command(0x8D);	
    lcd_write_data_value(0x03);

    lcd_write_command(0xB5);
    lcd_write_data_value(0x10);
    lcd_write_data_value(0x10);

    lcd_write_command(0xB6);
    lcd_write_data_value(0x00);
    lcd_write_data_value(0x00);

    lcd_write_command(0x36);	
    lcd_write_data_value(0x48);
    lcd_write_command(0x3A);	
    lcd_write_data_value(0x05);

    lcd_write_command(0x90);
    lcd_write_data_value(0x08);
    lcd_write_data_value(0x08);
    lcd_write_data_value(0x08);
    lcd_write_data_value(0x08);

    lcd_write_command(0xBA);			
    lcd_write_data_value(0x01);///TE width
    lcd_write_command(0xBD);			
    lcd_write_data_value(0x06);
    lcd_write_command(0xBC);	
    lcd_write_data_value(0x00);

    lcd_write_command(0xFF);
    lcd_write_data_value(0x60);
    lcd_write_data_value(0x01);
    lcd_write_data_value(0x04);

    lcd_write_command(0xC3);			
    lcd_write_data_value(0x40);
    lcd_write_command(0xC4);			
    lcd_write_data_value(0x13);

    lcd_write_command(0xC9);
    lcd_write_data_value(0x22);
    lcd_write_command(0xBE);
    lcd_write_data_value(0x11);

    lcd_write_command(0xE1);
    lcd_write_data_value(0x10);
    lcd_write_data_value(0x0E);

    lcd_write_command(0xDF);
    lcd_write_data_value(0x21);
    lcd_write_data_value(0x0c);
    lcd_write_data_value(0x02);


    lcd_write_command(0xF0);   
    lcd_write_data_value(0x4d);
    lcd_write_data_value(0x11);
    lcd_write_data_value(0x06);
    lcd_write_data_value(0x05);
    lcd_write_data_value(0x24);
    lcd_write_data_value(0x35);

    lcd_write_command(0xF1);    
    lcd_write_data_value(0x4a);
    lcd_write_data_value(0x70);
    lcd_write_data_value(0x72);
    lcd_write_data_value(0x36);
    lcd_write_data_value(0x37);
    lcd_write_data_value(0x6F);

    lcd_write_command(0xF2);   
    lcd_write_data_value(0x4d);
    lcd_write_data_value(0x11);
    lcd_write_data_value(0x06);
    lcd_write_data_value(0x05);
    lcd_write_data_value(0x24);
    lcd_write_data_value(0x35);

    lcd_write_command(0xF3);   
    lcd_write_data_value(0x4a);
    lcd_write_data_value(0x70);
    lcd_write_data_value(0x72);
    lcd_write_data_value(0x36);
    lcd_write_data_value(0x37);
    lcd_write_data_value(0x6F);

    lcd_write_command(0xED);
    lcd_write_data_value(0x1B);
    lcd_write_data_value(0x0B);

    lcd_write_command(0xAE);
    lcd_write_data_value(0x77);

    lcd_write_command(0xCD);
    lcd_write_data_value(0x63);

    lcd_write_command(0x70);
    lcd_write_data_value(0x07);
    lcd_write_data_value(0x07);
    lcd_write_data_value(0x04);
    lcd_write_data_value(0x0F);
    lcd_write_data_value(0x0F); 
    lcd_write_data_value(0x09);
    lcd_write_data_value(0x07);
    lcd_write_data_value(0x08);
    lcd_write_data_value(0x03);

    lcd_write_command(0xE8);			
    lcd_write_data_value(0x24);
    //lcd_write_command(0xE9);			
    //lcd_write_data_value(0x08);///spi 2 data
    /////////////////////////////////////////////

    lcd_write_command(0x60);
    lcd_write_data_value(0x38);
    lcd_write_data_value(0x14);
    lcd_write_data_value(0x2D);
    lcd_write_data_value(0x6D);
    lcd_write_data_value(0x38);
    lcd_write_data_value(0x16);
    lcd_write_data_value(0x2D);
    lcd_write_data_value(0x6D);

    lcd_write_command(0x61);
    lcd_write_data_value(0x3A);
    lcd_write_data_value(0x02);
    lcd_write_data_value(0x6D);
    lcd_write_data_value(0x2D);
    lcd_write_data_value(0xFA);
    lcd_write_data_value(0x0F);
    lcd_write_data_value(0x6D);
    lcd_write_data_value(0x6D);

    lcd_write_command(0x62);
    lcd_write_data_value(0x38);
    lcd_write_data_value(0x18);
    lcd_write_data_value(0x72);
    lcd_write_data_value(0x00);
    lcd_write_data_value(0x2D);
    lcd_write_data_value(0x6D);
    lcd_write_data_value(0x38);
    lcd_write_data_value(0x1C);
    lcd_write_data_value(0x72);
    lcd_write_data_value(0x04);
    lcd_write_data_value(0x2D);
    lcd_write_data_value(0x6D);

    lcd_write_command(0x63);
    lcd_write_data_value(0x7A);
    lcd_write_data_value(0x1F);
    lcd_write_data_value(0x72);
    lcd_write_data_value(0x0F);
    lcd_write_data_value(0x6D);
    lcd_write_data_value(0x6D);

    lcd_write_command(0x66);
    lcd_write_data_value(0xF4);
    lcd_write_data_value(0x00);
    lcd_write_data_value(0xCD);
    lcd_write_data_value(0x02);
    lcd_write_data_value(0x4C);
    lcd_write_data_value(0x5D);
    lcd_write_data_value(0xBA);
    lcd_write_data_value(0x01);
    lcd_write_data_value(0x00);
    lcd_write_data_value(0x00);

    lcd_write_command(0x67);
    lcd_write_data_value(0x00);
    lcd_write_data_value(0x2F);
    lcd_write_data_value(0x00);
    lcd_write_data_value(0x00);
    lcd_write_data_value(0x10);
    lcd_write_data_value(0xAB);
    lcd_write_data_value(0x91);
    lcd_write_data_value(0x80);
    lcd_write_data_value(0x20);
    lcd_write_data_value(0x98);

                        
    lcd_write_command(0x74);			
    lcd_write_data_value(0x10);	
    lcd_write_data_value(0x85);
    lcd_write_data_value(0x80);
    lcd_write_data_value(0x00);
    lcd_write_data_value(0x00);
    lcd_write_data_value(0x4E);
    lcd_write_data_value(0x00);

    lcd_write_command(0x98);
    lcd_write_data_value(0x3e);
    lcd_write_data_value(0x07);

    lcd_write_command(0x99);
    lcd_write_data_value(0x3e);
    lcd_write_data_value(0x07);

    lcd_write_command(0x35);
    lcd_write_data_value(0x00);

    lcd_write_command(0x21);
    LCD_DELAY_MS(120);
    lcd_write_command(0x11);
    LCD_DELAY_MS(120);
    lcd_write_command(0x29);

#else//new

    lcd_write_command( 0xEF ); 
    lcd_write_command( 0xEB ); 
    {
        uint8_t data[] = {0x14}; 
        lcd_write_data( data, sizeof(data) );
    }

    lcd_write_command( 0xFE );
    lcd_write_command( 0xEF );
    
    lcd_write_command( 0xEB ); 
    {
        uint8_t data[] = {0x14}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x84 ); 
    {
        uint8_t data[] = {0x40}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x85 ); 
    {
        uint8_t data[] = {0xff}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x86 ); 
    {
        uint8_t data[] = {0xff}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x87 ); 
    {
        uint8_t data[] = {0xff}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x88 ); 
    {
        uint8_t data[] = {0x0A}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x89 ); 
    {
        uint8_t data[] = {0x21}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x8A ); 
    {
        uint8_t data[] = {0x00}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x8B ); 
    {
        uint8_t data[] = {0x80}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x8C ); 
    {
        uint8_t data[] = {0x01}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x8D ); 
    {
        uint8_t data[] = {0x01}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x8E ); 
    {
        uint8_t data[] = {0xFF}; 
        lcd_write_data( data, sizeof(data) );
    }

    lcd_write_command( 0x8F ); 
    {
        uint8_t data[] = {0xFF}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    
    lcd_write_command( 0xB6 );
    {
        uint8_t data[] = {0x00, 0x20 }; 
        lcd_write_data( data, sizeof(data) );
    }

    lcd_write_command( 0x36 );
    {
        uint8_t data[] = {0x08}; 
        lcd_write_data( data, sizeof(data) );
    }
    lcd_write_command( 0x3A );
    {
        uint8_t data[] = {0x05};
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x90 );
    {
        uint8_t data[] = {0x08, 0x08, 0x08, 0x08}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xBD );
    {
        uint8_t data[] = {0x06}; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xBC );
    {
        uint8_t data[] = {0x00 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xFF );
    {
        uint8_t data[] = {0x60, 0x01, 0x04}; 
        lcd_write_data( data, sizeof(data) );
    }    
    
    lcd_write_command( 0xC3 );
    {
        uint8_t data[] = {0x13};  
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xC4 );
    {
        uint8_t data[] = {0x13 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xC9 );
    {
        uint8_t data[] = {0x22 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xBE );
    {
        uint8_t data[] = {0x11 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xE1 );
    {
        uint8_t data[] = {0x10, 0x0E }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xDF );
    {
        uint8_t data[] = { 0x21, 0x0c, 0x02 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xF0 );
    {
        uint8_t data[] = {0x45, 0x09, 0x08, 0x08, 0x26, 0x2A }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xF1 );
    {
        uint8_t data[] = {0x43, 0x70, 0x72, 0x36, 0x37, 0x6F }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xF2 );
    {
        uint8_t data[] = { 0x45, 0x09, 0x08, 0x08, 0x26, 0x2A }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xF3 );
    {
        uint8_t data[] = {0x43, 0x70, 0x72, 0x36, 0x37, 0x6F }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xED );
    {
        uint8_t data[] = {0x1B, 0x0B }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xAE );
    {
        uint8_t data[] = {0x77 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xCD );
    {
        uint8_t data[] = {0x63 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x70 );
    {
        uint8_t data[] = {0x07, 0x07, 0x04, 0x0E, 0x0F, 0x09, 0x07, 0x08, 0x03 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0xE8 );
    {
        uint8_t data[] = {0x34 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x62 );
    {
        uint8_t data[] = {0x18, 0x0D, 0x71, 0xED, 0x70, 0x70, 0x18, 0x0F, 0x71, 0xEF, 0x70, 0x70 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x63 );
    {
        uint8_t data[] = {0x18, 0x11, 0x71, 0xF1, 0x70, 0x70, 0x18, 0x13, 0x71, 0xF3, 0x70, 0x70 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x64 );
    {
        uint8_t data[] = {0x28, 0x29, 0xF1, 0x01, 0xF1, 0x00, 0x07 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x66 );
    {
        uint8_t data[] = {0x3C, 0x00, 0xCD, 0x67, 0x45, 0x45, 0x10, 0x00, 0x00, 0x00 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x67 );
    {
        uint8_t data[] = {0x00, 0x3C, 0x00, 0x00, 0x00, 0x01, 0x54, 0x10, 0x32, 0x98 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x74 );
    {
        uint8_t data[] = {0x10, 0x85, 0x80, 0x00, 0x00, 0x4E, 0x00 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x98 );
    {
        uint8_t data[] = {0x3e, 0x07 }; 
        lcd_write_data( data, sizeof(data) );
    }
    
    lcd_write_command( 0x35 );
    lcd_write_command( 0x21 );
    
    LCD_DELAY_MS( 40 ); 

#if 0
    lcd_write_command( 0x28 ); // turn off 
    lcd_write_command( 0x10 ); // sleep in 
#else 
    lcd_write_command( 0x11 );
    platform_delay_ms( 20 ); 
    lcd_write_command( 0x29 );  // display ON 
    platform_delay_ms( 20 ); 
#endif 
#endif
}


void em_lcd_init(void)
{
    //if( !is_initialized )
    {
        //is_initialized = true;
        lcd_common_init();
        driver_init();
    }
}

void em_lcd_power_off(void)
{
    lcd_write_command( 0x28 ); // turn off 
    LCD_DELAY_MS( 20 );
    lcd_write_command( 0x10 ); // sleep in 
    LCD_DELAY_MS( 20 );
    xDLPS_reset( lcd_dlps_index );
}

void em_lcd_power_on(void)
{
    lcd_gdma_init();
    lcd_write_command( 0x11 ); // sleep out 
    LCD_DELAY_MS( 40 );
    lcd_write_command( 0x29 ); // turn on   
    LCD_DELAY_MS( 20 );
}
void em_lcd_sleep_out(void)
{
    lcd_gdma_init();
    lcd_write_command( 0x11 ); 
    LCD_DELAY_MS( 40 );
    xDLPS_set( lcd_dlps_index );
}
void em_lcd_turn_on(void)
{
    lcd_write_command( 0x29 );
    LCD_DELAY_MS( 40 );
}
GUI_RAM_CODE
void em_lcd_set_window(int16_t x0, int16_t y0, int16_t w, int16_t h)
{
    uint16_t xstart = x0;
    uint16_t ystart = y0;
    uint16_t xend = x0 + w - 1;
    uint16_t yend = y0 + h - 1;
    
    // column address set
    lcd_write_command(0x2A); { // CASET
        uint8_t data[] = { (xstart >> 8) & 0xFF , xstart & 0xFF, (xend >> 8) & 0xFF, xend & 0xFF };
        lcd_write_data(data, sizeof(data));
    }
    // row address set
    lcd_write_command(0x2B); {// RASET
        uint8_t data[] = { (ystart >> 8) & 0xFF, ystart & 0xFF, (yend >> 8) & 0xFF, yend & 0xFF };
        lcd_write_data(data, sizeof(data));
    }
    // write to RAM
    lcd_write_command(0x2C); // RAMWR  
}
GUI_RAM_CODE
void em_lcd_write(uint8_t* p_buffer, uint32_t size)
{   
    if( lcd_wrctl.isbusy )
    {
        return;
    }
    
    lcd_wrctl.isbusy = true; 
    lcd_wrctl.block_write = false;
    lcd_wrctl.pdata = (uint8_t*)p_buffer;
    lcd_wrctl.offset = 0;
    lcd_wrctl.size = size;
    
    uint32_t chunk_remain = size; 
    if( chunk_remain > LCD_XFER_MAX_SIZE )
    {
        chunk_remain = LCD_XFER_MAX_SIZE; 
    }
    lcd_wrctl.offset = chunk_remain;
    LCD_SEND_DATA_ASYNC( lcd_wrctl.pdata, chunk_remain );
}

/*
    p_buffer -> LCD Memory 
    offset   -> next block offset 
    size     -> size of block  
    rows     -> block count 
*/
GUI_RAM_CODE
void em_lcd_write_block( uint8_t* p_buffer, int16_t offset, uint16_t size, int16_t count )
{
    if( lcd_wrctl.isbusy )
    {
        return;
    }
    
    lcd_wrctl.isbusy                = true;
    lcd_wrctl.block_write           = true; 
    lcd_wrctl.pdata                 = (uint8_t*)p_buffer;
    lcd_wrctl.offset                = 0; 
    lcd_wrctl.size                  = size; 
    
    lcd_wrctl.blocks.used           = 0;
    lcd_wrctl.blocks.size           = size;
    lcd_wrctl.blocks.count          = count;
    lcd_wrctl.blocks.offset         = offset;
    
    uint32_t chunk_remain = size; 
    if( chunk_remain > LCD_XFER_MAX_SIZE )
    {
        chunk_remain = LCD_XFER_MAX_SIZE; 
    }
    lcd_wrctl.offset                = chunk_remain; 
    LCD_SEND_DATA_ASYNC( lcd_wrctl.pdata, chunk_remain );
//    LOG_INFO1("[LCD]: block write count = %d", count );
}

void em_lcd_draw_point( int16_t x, int16_t y, uint16_t color )
{
    em_lcd_set_window(x, y, 1, 1 );
    LCD_SEND_DATA( (uint8_t*)&color, 2);
}

void em_lcd_wait_transfer_completed(void)
{
    while( lcd_wrctl.isbusy );
}

bool em_lcd_check_transfer_completed(void)
{
    return lcd_wrctl.isbusy; 
}

